package com.rajesh.messageservice.crack;

import android.annotation.SuppressLint;
import android.content.Context;
import android.telephony.TelephonyManager;

import com.rajesh.messageservice.helper.GlobalConfig;

import org.apache.commons.codec.digest.DigestUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 获取用户 Uin
 * 计算用户文件夹名称
 * 获取终端设备编号
 * 计算数据库秘钥
 * 获取当前微信用户的数据文件
 * 获取微信下所有文件路径集合
 */
public final class WeChatCracker {
    final String TAG = "WeChatCracker";
    private static final String WE_CHAT_DIR = "/data/data/com.tencent.mm";
    private static String _dir = WE_CHAT_DIR + File.separator + "MicroMsg";
    public static String SYSTEM_INFO_CFG = _dir + File.separator + "systemInfo.cfg";
    //微信用户 uin 编码，存储在微信程序目录下的 systemInfo.cfg 文件中
    public static String uin = null;
    public static String dbPath = null;
    public static String pragmaKey = null;

    /**
     * 读取微信目录下的 systemInfo.cfg 文件， 获取 Uin
     *
     * @author Rajesh
     * @exception SecurityException 如果此发生此异常，则表示目标文件访问权限未设置为 777
     * @exception IOException
     * @return 用户微信 uin 编码
     * */
    public static String getUin() throws IOException {
        if(uin != null && uin.trim() != ""){
            return uin;
        }

        FileInputStream fileInputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            File systemInfo = new File(SYSTEM_INFO_CFG);
            if(!systemInfo.canRead()){
                //如果对目标文件无权限执行 修改目标文件访问权限为 777
                CommandExecutor.getFilesAccessPermission(SYSTEM_INFO_CFG);
            }

            fileInputStream = new FileInputStream(SYSTEM_INFO_CFG);
            objectInputStream = new ObjectInputStream(fileInputStream);
            Map map = (Map) objectInputStream.readObject();
            uin = map.get(1).toString();
        }catch (SecurityException e) {
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(objectInputStream != null)
                objectInputStream.close();

            if(fileInputStream != null)
                fileInputStream.close();
        }
        return uin;
    }

    /**
     * 根据用户 Uin 编码计算出用户聊天记录文件存储文件夹名称
     *
     * @author Rajesh
     * @return 用户聊天记录文件存储文件夹名称
     * */
    public static String computeUserDir() throws IOException {
        return DigestUtils.md5Hex("mm" + getUin());
    }

    /**
     * 获取终端设备编号
     *
     * @author Rajesh
     * @param context 获取 TELEPHONY_SERVICE 服务
     * @return 终端设备编号
     * */
    @SuppressLint("MissingPermission")
    private static String getDeviceId(Context context){
        // android version >= 10 -> 1234567890ABCDEF
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        return telephonyManager.getDeviceId();
    }

    /**
     * TODO： 判断 android 版本， 如果大于等于 10 ， 则返回 FAKE_IMEI  1234567890ABCDEF
     * */
//    @SuppressLint("MissingPermission")
//    public static String getIMEI(Context context) {
//        try {
//            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
//            String deviceId = telephonyManager.getDeviceId();
//            if(TextUtils.isEmpty(deviceId)){
//                return "1234567890ABCDEF";
//            }
//            return deviceId;
//        } catch (Exception e) {
//            Log.e("IMEI", e.toString());
//            return "";
//        }
//    }

    /**
     * 根据用户 Uin 编码以及终端设备编号计算 sqlcipher 数据库的 pragma key
     *
     * @author Rajesh
     * @param context android 上下文
     * @return sqlcipher 数据库的 pragma key
     * */
    public static String computePragmaKey(Context context) throws IOException {
        if(pragmaKey != null && pragmaKey.trim() != ""){
            return pragmaKey;
        }
        pragmaKey = DigestUtils.md5Hex(getDeviceId(context) + getUin()).substring(0, 7);
        return pragmaKey;
    }

    /**
     * 获取指定用户 sqlcipher 数据库文件路径
     *
     * @author Rajesh
     * @return 数据库文件路径
     * */
    public static String getUserDataBasePath(boolean changeAccess) throws IOException {
        if(dbPath != null && dbPath.trim() != ""){
            return dbPath;
        }

        GlobalConfig.Identity = computeUserDir();
        String path = _dir + File.separator + GlobalConfig.Identity + File.separator + "EnMicroMsg.db";
        File database = new File(path);
        if(changeAccess || !database.canExecute()){
            CommandExecutor.executeRootCommand("chmod 777 " + path);
        }

        dbPath = path;
        return dbPath;
    }

    /**
     * 获取微信目录下所有文件路径
     *
     * @author Rajesh
     * @param basePath 递归起始目录
     * @return 目录集合
     * */
    public static List<String> getWeChatFiles(String basePath){
        List<String> result = new ArrayList<>();
        File file = new File(basePath);
        if(file.isDirectory()){
            result.add(file.getAbsolutePath());
            File[] files = file.listFiles();
            for (File child: files) {
                result.addAll(getWeChatFiles(child.getAbsolutePath()));
            }
        }
        if(file.isFile()){
            result.add(file.getAbsolutePath());
        }
        return result;
    }

}
